#include <stdlib.h>
#include <stdio.h>
#include <nds.h>
#include <maxmod9.h>

// common headers
#include "common.h"		// global

// local headers
#include "main.h"

#include "tone.h"

sSInfos infos;
mm_stream stream;
void *inid=NULL;

u32 sine=0;
u32 sine_freq=1000;

mm_word on_stream_request(mm_word length, mm_addr dest, mm_stream_formats format) {
	s16 *target=dest;
	int len;

	if(infos.position+length>infos.duration) {
		length=infos.duration-infos.position;
		infos.position=infos.duration;

		std->iprintf("end of stream\n");
	}
	else infos.position+=length;

	for(len=length; len; len--) {
		*target++=nds->sin(sine)<<2;

		sine+=sine_freq;
	}

	return length;
}

int assign(FILE *f) {
	if(!f || inid) return 1;

	std->bzero(&infos, sizeof(sSInfos));
	std->bzero(&stream, sizeof(mm_stream));

	stream.sampling_rate	= 32768;				// sampling rate = 32768Hz
	stream.buffer_length	= 1200;					// buffer length = 1200 samples
	stream.callback			= on_stream_request;	// set callback function
	stream.format			= MM_STREAM_16BIT_MONO;	// format = mono 16-bit
	stream.manual			= false;				// use auto filling

	infos.channels=1;
	infos.samplingrate=32768;
	infos.position=0;
	infos.flags=S_STOPPED;
	infos.fd=f;

	int ret;

	inid=ini->open(infos.fd, libres.extid);
	if(!inid) return 1;

	ret=ini->get_integer(inid, "tone", "duration", (s32 *)&infos.duration);
	if(ret) {
		ini->close(inid);
		inid=NULL;
		return 1;
	}

	return 0;
}

int getInfos(sSInfos *i) {
	if(!i) return 0;

	std->memcpy(i, &infos, sizeof(sSInfos));

	return 0;
}

int getTags(sSTags *t) {
	return 1;
}

int setTags(sSTags *t) {
	return 1;
}

int play() {
	if(!inid) return 1;

	int ret;

	ret=ini->get_integer(inid, "tone", "freq", (s32 *)&sine_freq);
	if(ret) {
		ini->close(inid);
		inid=NULL;
		return 1;
	}

	if(mm->StreamOpen(&stream)) return 1;

	infos.flags=S_PLAYING;

	return 0;
}

int pause() {
	if(!inid) return 1;

	switch(infos.flags&S_STATES_MASK) {
	case S_PLAYING:
		mm->StreamClose();
		infos.flags=S_PAUSED;
		break;
	case S_PAUSED:
		if(mm->StreamOpen(&stream)) return 1;	// another sound is already playing ?
		infos.flags=S_PLAYING;
		break;
	default:
		return 1;
	}

	return 0;
}

int stop() {
	if(!inid) return 1;

	switch(infos.flags&S_STATES_MASK) {
	case S_PLAYING:
	case S_PAUSED:
		mm->StreamClose();
		infos.flags=S_STOPPED;
	case S_STOPPED:
		return 0;
	default:
		return 1;
	}
}

int seek(s32 r, u8 p) {
	return 1;
}

u32 position2ms(u32 p) {
	return p;
}

u32 ms2position(u32 ms) {
	return ms;
}

int deassign() {
	stop();

	if(inid) ini->close(inid);
	inid=NULL;

	return 0;
}

